package net.jingkao.app.common;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.jingkao.app.bean.annotation.WebService;
import net.jingkao.app.common.Params.Param;
import android.util.Log;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

/**
 * WebService代理
 * @author chao
 *
 */
public class WebServices implements InvocationHandler {
	
	static final String TAG = "WebServices";
	private final String appkey = "4028829919";
	
	static Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
	
	/**
	 * 产生WebService的代理对象
	 * @param webServiceInterface
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static synchronized <T> T proxy(Class<T> webServiceInterface){
		Object serv = services.get(webServiceInterface);
		if(serv != null){
			return (T)serv;
		}
		serv = Proxy.newProxyInstance(WebServices.class.getClassLoader(), new Class[]{
			webServiceInterface
		}, new WebServices());
		
		services.put(webServiceInterface, serv);
		return (T)serv;
	}
	
	/**
	 * 检查errorCode
	 * @param dataJson
	 * @return
	 */
	private boolean check(JsonObject dataJson){
		
		return true;
	}
	
	private Object getReq(WebService ws, Object proxyObj, Method method, Object[] args){
		String serviceUrl = ws.url();
		Param params = Params.add("app_key", appkey);
		if(ws.args() != null){
			for(int i = 0 ; i < ws.args().length && i < args.length; i++){
				params.add(ws.args()[i], args[i]);
			}
		}
		
		JsonObject dataJson = WebClient.get(serviceUrl, params).getAsJson();
		Log.d(TAG, dataJson.toString());
		if(check(dataJson)){
			Class returnType = method.getReturnType();
			if(returnType.isAssignableFrom(List.class)){
				JsonArray jsonArr = dataJson.get("data").getAsJsonArray();
				List list = new ArrayList(jsonArr.size());
				for(JsonElement e : jsonArr){
					try{
						list.add(JsonUtil.convertTo(e.getAsJsonObject(), ws.bean()));
					}catch(Exception ex){
						Logger.getLog(this).e(ex, "The data responsed is not JSON: %s", e);
					}
				}
				return list;
			}else{
				Object obj = JsonUtil.convertTo(dataJson.get("data").getAsJsonObject(), ws.bean());
				return obj;
			}
			
		}else{
			return null;
		}
	}
	
	private Object postReq(WebService ws, Object proxyObj, Method method, Object[] args){
		String serviceUrl = ws.url();
		Param params = Params.add("app_	key", appkey);
		if(ws.args() != null){
			for(int i = 0 ; i < ws.args().length && i < args.length; i++){
				params.add(ws.args()[i], args[i]);
			}
		}
		
		JsonObject dataJson = WebClient.post(serviceUrl, params, null).getAsJson();
		Log.d(TAG, dataJson.toString());
		if(check(dataJson)){
			Class returnType = method.getReturnType();
			if(returnType.isAssignableFrom(List.class)){
				JsonArray jsonArr = dataJson.get("data").getAsJsonArray();
				List list = new ArrayList(jsonArr.size());
				for(JsonElement e : jsonArr){
					try{
						list.add(JsonUtil.convertTo(e.getAsJsonObject(), ws.bean()));
					}catch(Exception ex){
						Logger.getLog(this).e(ex, "The data responsed is not JSON: %s", e);
					}
				}
				return list;
			}else{
				Object obj = JsonUtil.convertTo(dataJson.get("data").getAsJsonObject(), ws.bean());
				return obj;
			}
			
		}else{
			return null;
		}
	}

	/**
	 * proxy调用
	 */
	@Override
	public Object invoke(Object proxyObj, Method method, Object[] args)
			throws Throwable {
		WebService ws = method.getAnnotation(WebService.class);
		if(ws == null){
			Log.e(TAG, String.format("The method[%s] does not mark @WebService", method));
			return null;
		}
		MobileTracer.onEventBegin(null, "WebService[%s] invoke", ws.url());
		try{
			switch (ws.method()) {
				case WebService.GET:
					return getReq(ws, proxyObj, method, args);
		
				case WebService.POST:
					return postReq(ws, proxyObj, method, args);
						
				default:
					Log.w(TAG, "Incorrect method");
					return null;
			}
		}catch(AppException e){
			Logger.getLog(WebServices.class).e(e);
			return null;
		}finally{
			MobileTracer.onEventEnd(null, "WebService[%s] invoke", ws.url());
		}
	}
	
	
}
